package com.chenfan.mcn.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.common.vo.Response;
import com.chenfan.mcn.clients.baseinfo.BaseCustomer;
import com.chenfan.mcn.clients.baseinfo.BaseInfoClient;
import com.chenfan.mcn.clients.privilege.*;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.constant.NumberCst;
import com.chenfan.mcn.dao.CalculationDevidedMapper;
import com.chenfan.mcn.dao.ContractExcutionOrderMapper;
import com.chenfan.mcn.dao.IncomeContractMapper;
import com.chenfan.mcn.dao.QuarterMapper;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.mcn.model.McnPage;
import com.chenfan.mcn.model.Quarter;
import com.chenfan.mcn.model.common.PageInfo;
import com.chenfan.mcn.model.dto.UnPayBackContractDTO;
import com.chenfan.mcn.model.vo.*;
import com.chenfan.mcn.service.DataStatisticsService;
import com.chenfan.mcn.utils.RpcUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * author:   tangwei
 * Date:     2021/3/9 13:55
 * Description: 首页数据统计
 *
 * @author 2212
 */
@Service
public class DataStatisticsServiceImpl implements DataStatisticsService {

    @Autowired
    private IncomeContractMapper incomeContractMapper;

    @Autowired
    private BaseInfoClient baseInfoClient;

    @Autowired
    private ContractExcutionOrderMapper contractExcutionOrderMapper;

    @Autowired
    private CalculationDevidedMapper calculationDevidedMapper;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Autowired
    private QuarterMapper quarterMapper;

    private final static String SEMICOLON = ";";

    /**
     * 客户投放金额（本月）
     *
     * @param page {@link McnPage}
     * @return
     */
    @Override
    public Page<CustomerInvestmentAmount> customerInvestmentAmount(McnPage<CustomerInvestmentAmount> page) {
        Page<CustomerInvestmentAmount> customerInvestmentAmounts = incomeContractMapper.customerInvestmentAmount(page);
        List<Long> customerIdList = customerInvestmentAmounts.getRecords().stream().map(CustomerInvestmentAmount::getCustomerId).collect(Collectors.toList());
        Map<Long, BaseCustomer> customerMapping = Objects.requireNonNull(baseInfoClient.getMcnCustomerByIds(customerIdList)).getObj();
        customerInvestmentAmounts.getRecords().forEach(x -> {
            BaseCustomer baseCustomer = customerMapping.get(x.getCustomerId());
            if (baseCustomer == null) {
                throw new BusinessException(McnErrorCode.CUSTOMER_ID_NOT_EXIST.format(x.getCustomerId().toString()));
            }
            x.setCustomerName(baseCustomer.getCustomerNameC());

        });
        return customerInvestmentAmounts;
    }

    /**
     * 红人月度执行单数量&金额（本月）
     *
     * @param type {@link Integer}
     * @param page {@link McnPage}
     * @return
     */
    @Override
    public Page<RedManMonthlyExecution> redManMonthlyExecution(Integer type, McnPage<RedManMonthlyExecution> page) {
        return contractExcutionOrderMapper.redManMonthlyExecution(type, page);
    }


    @Override
    public BigDecimal incomeContractTotalAmount() {
        BigDecimal totalAmount = incomeContractMapper.incomeContractTotalAmount(DateUtil.beginOfMonth(new Date()), DateUtil.endOfMonth(new Date()));
        if (totalAmount == null) {
            totalAmount = BigDecimal.ZERO;
        }
        BigDecimal tenThousand = new BigDecimal(10000);
        return totalAmount.divide(tenThousand, 1, BigDecimal.ROUND_HALF_UP).setScale(1, BigDecimal.ROUND_HALF_UP);
    }

    @Override
    public BigDecimal excutedAmount() {
        BigDecimal excutedAmount = calculationDevidedMapper.excutedAmount(DateUtil.beginOfMonth(new Date()), DateUtil.endOfMonth(new Date()));
        if (excutedAmount == null) {
            excutedAmount = BigDecimal.ZERO;
        }
        BigDecimal tenThousand = new BigDecimal(10000);
        return excutedAmount.divide(tenThousand, 1, BigDecimal.ROUND_HALF_UP).setScale(1, BigDecimal.ROUND_HALF_UP);
    }

    @Override
    public List<ExcutionOrderCountVO> totalCount(Integer type) {
        return contractExcutionOrderMapper.totalCount(type, DateUtil.beginOfMonth(new Date()), DateUtil.endOfMonth(new Date()));
    }


    /**
     * 合同签订情况（本月）
     *
     * @return {@link List<ContractSigning>}
     */
    @Override
    public List<ContractSigning> contractSigning() {
        return incomeContractMapper.contractSigning();
    }

    /**
     * 部门业绩情况(本月)
     *
     * @return {@link List<DepartmentPerformance>}
     */
    @Override
    public List<DepartmentPerformance> departmentPerformance() {
        List<SDepartment> sDepartments = Objects.requireNonNull(privilegeClient.getBusinessDepartment()).getObj();
        List<Long> departmentIds = sDepartments.stream().map(SDepartment::getDepartmentId).collect(Collectors.toList());
        List<DepartmentPerformance> departmentPerformances = incomeContractMapper.departmentPerformance(departmentIds);
        Map<Long, SDepartment> sDepartmentMap = Objects.requireNonNull(privilegeClient.getDepartmentByIds(departmentIds)).getObj();
        if (Objects.nonNull(sDepartmentMap)) {
            departmentPerformances.forEach(x -> {
                if (Objects.nonNull(x.getDepartmentId())) {
                    x.setDepartmentName(sDepartmentMap.get(x.getDepartmentId()).getDepartmentName());
                }
            });
        }
        List<DepartmentPerformance> list = departmentPerformances.stream().sorted(Comparator.comparing(DepartmentPerformance::getDepartmentName)).collect(Collectors.toList());
        System.out.println("排序------------------->" + list);
        return departmentPerformances;
    }

    @Override
    public PageInfo<UnPayBackContractVO> unPayBackContract(UnPayBackContractDTO dto) {
        isDepartmentHead(dto);
        Page<UnPayBackContractVO> page = incomeContractMapper.unPayBackContract(new Page<>(dto.getPageNum(), dto.getPageSize()), dto);
        if (CollectionUtil.isNotEmpty(page.getRecords())) {
            List<Long> customerIds = page.getRecords().stream().map(UnPayBackContractVO::getCustomerId)
                    .collect(Collectors.toList());
            Map<Long, BaseCustomer> customerMap = baseInfoClient.getMcnCustomerByIds(customerIds).getObj();
            page.getRecords().forEach(x -> {
                if (customerMap.containsKey(x.getCustomerId())) {
                    x.setCustomerName(customerMap.get(x.getCustomerId()).getCustomerNameC());
                }
            });
        }
        return PageInfo.toPageInfo(page);
    }

    private void isDepartmentHead(UnPayBackContractDTO unPayBackContractDTO) {
        Long userId = UserVoContextHolder.getUserId();
        Response<Map<Long, DepartmentVO>> mapResponse = privilegeClient.getDepartmentHeadByUserIds(Collections.singletonList(userId));
        Map<Long, DepartmentVO> voMap = RpcUtil.getObjException(mapResponse, "privilegeClient 权限系统异常");
        DepartmentVO departmentVO = voMap.get(userId);
        if (Objects.nonNull(departmentVO) && Objects.nonNull(departmentVO.getDepartmentHeadId()) && departmentVO.getDepartmentHeadId().equals(userId)) {
            unPayBackContractDTO.setDepartmentHeadState(NumberCst.ONE);
        }
    }

    @Override
    public GrandAmountVO grandAmount(UnPayBackContractDTO unPayBackContractDTO) {
        isDepartmentHead(unPayBackContractDTO);
        return incomeContractMapper.grandAmount(unPayBackContractDTO);
    }

    @Override
    public PageInfo<UnPayBackRankVO> unPayBackRank(UnPayBackContractDTO dto) {
        isDepartmentHead(dto);
        List<SDepartment> sDepartments = privilegeClient.getBusinessDepartment().getObj();
        List<Long> departmentIds = sDepartments.stream().map(SDepartment::getDepartmentId).collect(Collectors.toList());
        Response<List<SUser>> listResponse = privilegeClient.getUserByDepartmentId(departmentIds);
        List<SUser> sUsers = RpcUtil.getObjException(listResponse, "privilegeClient 权限异常");
        List<Long> userIds = sUsers.stream().map(SUser::getUserId).collect(Collectors.toList());
        Page<UnPayBackRankVO> page = incomeContractMapper.unPayBackRank(new Page<>(dto.getPageNum(), dto.getPageSize()), userIds, dto);
        if (CollectionUtil.isNotEmpty(page.getRecords())) {
            List<Long> userIdList = page.getRecords().stream().map(UnPayBackRankVO::getUserId).collect(Collectors.toList());
            List<SUserVo> userList = privilegeClient.getDepartmentByUserIds(userIdList).getObj();
            Map<Long, String> usernameMap = userList.stream().collect(Collectors.toMap(SUserVo::getUserId, SUserVo::getUsername));
            page.getRecords().forEach(x -> {
                if (usernameMap.containsKey(x.getUserId())) {
                    x.setUserName(usernameMap.get(x.getUserId()));
                }
            });
        }
        return PageInfo.toPageInfo(page);
    }

    @Override
    public Page<RankingOfCooperativeBrands> rankingOfCooperativeBrands(McnPage<RankingOfCooperativeBrands> page) {
        return incomeContractMapper.rankingOfCooperativeBrands(new Page<>(page.getPageNum(), page.getPageSize()), page.getPageNum(), page.getPageSize(), UserVoContextHolder.defaultTenantId());
    }

    @Override
    public Page<DepartmentCollectionRate> departmentCollectionRate(McnPage<DepartmentCollectionRate> page) {
        Date now = new Date();
        Quarter quarter = quarterMapper.selectOne(Wrappers.lambdaQuery(Quarter.class).le(Quarter::getStartTime, now).ge(Quarter::getEndTime, now));
        Page<DepartmentCollectionRate> dataList = incomeContractMapper.summaryReturn(new Page<>(page.getPageNum(), page.getPageSize()), quarter.getStartTime(), quarter.getEndTime());
        if (CollectionUtils.isNotEmpty(dataList.getRecords())) {
            List<Long> departmentIds = dataList.getRecords().stream().map(DepartmentCollectionRate::getDepartmentId).distinct().collect(Collectors.toList());
            Map<Long, SDepartment> sDepartmentMap = Objects.requireNonNull(privilegeClient.getDepartmentByIds(departmentIds)).getObj();
            List<SDepartment> sDepartments = new ArrayList<>(sDepartmentMap.values());
            List<Long> departmentHeadIds = sDepartments.stream().map(SDepartment::getDepartmentHeadId).filter(Objects::nonNull).collect(Collectors.toList());
            List<SUserVo> sUserVos = Objects.requireNonNull(privilegeClient.getDepartmentByUserIds(departmentHeadIds)).getObj();
            Map<Long, SUserVo> voMap = sUserVos.stream().collect(Collectors.toMap(SUserVo::getUserId, sUserVo -> sUserVo));
            dataList.getRecords().forEach(x -> {
                if (Objects.nonNull(sDepartmentMap.get(x.getDepartmentId()))) {
                    x.setDepartmentName(sDepartmentMap.get(x.getDepartmentId()).getDepartmentName());
                }
                if (Objects.nonNull(sDepartmentMap.get(x.getDepartmentId())) && Objects.nonNull(voMap.get(sDepartmentMap.get(x.getDepartmentId()).getDepartmentHeadId()))) {
                    x.setDepartmentHeaderName(voMap.get(sDepartmentMap.get(x.getDepartmentId()).getDepartmentHeadId()).getUsername());
                }
                if (BigDecimal.ZERO.compareTo(x.getTotalBusinessAmount()) == 0) {
                    x.setReturnRate(BigDecimal.ZERO);
                } else if (BigDecimal.ZERO.compareTo(x.getTotalPaybackAmount()) == 0) {
                    x.setReturnRate(BigDecimal.ZERO);
                } else {
                    // 部门回款率统计逻辑：
                    //  1、本季度签单金额：本部门下（收入合同所属部门为本部门）【收入合同创建时间为本季度时间内】（审批通过状态）的【商务确认合同金额】累计。
                    //  2、本季度实际回款金额：本部门下（收入合同所属部门为本部门）【收入合同创建时间为本季度时间内】（审批通过状态）的【回款金额】累计。
                    //  3、回款率=本季度实际回款金额/本季度签单金额（百分号前面数字四舍五入保留两位小数）
                    x.setReturnRate(x.getTotalPaybackAmount().divide(x.getTotalBusinessAmount(), 4, BigDecimal.ROUND_HALF_UP));
                }
            });
        }
        return dataList;
    }
}